package org.jugile.jsontmpl.domain;

import java.util.ArrayList;
import java.util.List;
import java.util.HashSet;
import java.util.Set;

import org.apache.log4j.Logger;
import org.jugile.util.*;

import org.jugile.jsontmpl.common.*;



public abstract class ParamBase extends Entity {
	static Logger log = Logger.getLogger(ParamBase.class);
	
	public DOH getDoh() { return new DOH("Param",getId()); }

	public void reindex(Domain d) {}
	
	// --- fields ---

	private int num;
	public int getNum() { return num; }
	public Param setNum(int v) { num = v; d()._modified(this); return (Param)this; }
 	private String value;
	public String getValue() { return value; }
	public Param setValue(String v) { value = v; d()._modified(this); return (Param)this; }
  

 
	// --- connections ---

 
 
 

	// --- 1 - n ----

 

	// --- n - 1 ----

	private Fld fld;
	public Fld getFld() { return fld; }
	public Param setFld(Fld v) {
		d()._modified(this);
		return mapFld(v);
	}
	protected Param mapFld(Fld v) { 
		if (fld != null) fld._removeParam((Param)this);
		if (v != null) v._addParam((Param)this);
		fld = v;
		return (Param)this;
	}

 

	// --- n - n ----
 
	// --- life cycle methods ---
	public void delete() { delete(true); }
	public void delete(boolean ondelete) {
		if (ondelete) this.onDelete();
 		Fld o1 = getFld();
		if (o1 != null) o1.removeParam((Param)this);  
   		d().deleteParam(getId());
 		d()._deleted(this);
	}

	public void onDelete() {} // override 
	public void onLoad(IDomain d) {} // override
	public void onWrite() {} // override
	public void onDeleteEvent() {} // override
	public void onSave() {} // override - not implemented yet
	
	public String toString() {
		String res = "";
		res += nn(num) + ";";
 		res += nn(value) + ";";
  		return res;
	}
	
	
	public final static String[] _flds = {
		"num",
		"value",
  		"Fld",
 	};
	public static String[] flds() { return _flds; }
	
	public void parseNum(String v) {
		setNum(Jugile.parseIntSafe(v)); return;
 	}
	public void parseValue(String v) {
	    if ("-".equals(v)) v = null;
		setValue(v); return;
 	}
 
 
	public void parseFld(String id) {
		if ("-".equals(id)) setFld(null);
		else setFld( (Fld)d().getOrCreate("Fld", id));
	}
 
	// ----- db persistence -----

	protected static String _getSelectFlds() {
		Buffer buf = new Buffer();
		buf.add("id_f,ts,host,vers");
		for (String fld : _flds) {
			buf.add(","+fld+"_f");
		}
		return buf.toString();
	}
	protected String _getUpdateFlds() {
		Buffer buf = new Buffer();
		for (int i = 0; i < _flds.length; i++) {
			if (i > 0) buf.add(",");
			buf.add(_flds[i]+"_f=?");
		}
		return buf.toString();		
	}
	
	protected void _readFlds(Domain d, List row) {
		_modified = row.get(1)==null?null:new Time((java.util.Date)row.get(1));
		String host = (String)row.get(2);
		setVersion((Integer)row.get(3));
		num = row.get(4)==null?0:(Integer)row.get(4);
		value = (String)row.get(5);
  		mapFld(row.get(6)==null?null:Fld.getOrCreate(d,(Integer)row.get(6)));
 
		// call onLoad
		onLoad(d);
		setVirgin(false);
	}

	
	protected void _writeFlds(DBConnection c) throws Exception {
		onWrite();
		// is it insert or update?
		if (isVirgin()) {
			c.prepare("insert into "+ _tablename+" set id_f=?,host=?,vers=?," + _getUpdateFlds());
			c.param(Long.parseLong(getId()));
			c.param(Domain.getHostName());
			c.param(1L);

			setWriteParams(c);
			
			try {
				c.execute();
			} catch(Exception se) {
				log.error("Failed to insert writeFlds Param: " + getId());
				throw se;
			}
			setVersion(1L);
		} else {
			c.prepare("update "+ _tablename+" set host=?,vers=?," + _getUpdateFlds() + " where id_f=? AND vers=?");
			c.param(Domain.getHostName());
			c.param(getVersion()+1L); // increment db version
			
			setWriteParams(c);
			
			c.param(Long.parseLong(getId()));
			c.param(getVersion());
			try {
				int res = c.execute();
				if (res != 1) {
					fail("object not found: Param " + getId() + " " + getVersion());
				}
			} catch(Exception se) {
				log.error("Failed to update writeFlds Param: " + getId());
				throw se;
			}
			// increment mem object versions when db commit is ok
		}
	}

	private void setWriteParams(DBConnection c) throws Exception {
		c.param(getNum());
		c.param(trim(getValue(),300));
  		c.param(getFld());
 	}

	private final static String _tablename = "param_t";
	protected String _getTableName() { return _tablename; }

	protected static int _readAllUpdates(Domain d, DBConnection c, Time ts, String host) throws Exception {
		if (host == null) {
			c.prepare("select "+Param._getSelectFlds()+" from "+_tablename+" where ts >= ?");			
			c.param(ts);
		} else {
			c.prepare("select "+Param._getSelectFlds()+" from "+_tablename+" where ts >= ? AND host != ?");			
			c.param(ts);
			c.param(host);
		}
		int count = 0;
		for (List row : c.select()) {
			long id = (Integer)row.get(0);
			Param o = getOrCreate(d,id);
			o._readFlds(d,row);
			count++;
		}
		return count;
	}
	
	private Time _modified;
	public Time getModifiedTime() { return _modified; }
	
	protected static Param getOrCreate(Domain d, long id) {
		Param o = d.getParam(id);
		if (o == null) o = d._createEmptyParam(id);
		return o;
	}

}